package tidb

import (
	"douhu_backend/internal/controller/common"
	"douhu_backend/internal/dao"
	model "douhu_backend/internal/model/douyin"
	"errors"

	"gorm.io/gorm"
)

type homepageDAO struct {
	db *gorm.DB
}

// NewHomepageDAO 创建HomepageDAO实例（工厂方法）
func NewHomepageDAO(db *gorm.DB) dao.HomepageDAO {
	return &homepageDAO{db: db}
}

// Profile operations
func (h *homepageDAO) CreateProfile(profile *model.Profile) error {
	return h.db.Create(profile).Error
}

func (h *homepageDAO) GetProfileByID(id string) (*model.Profile, error) {
	var profile model.Profile
	err := h.db.Where("id = ?", id).First(&profile).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, nil
	}
	return &profile, err
}

func (h *homepageDAO) GetProfiles(pagination *common.Pagination) (*common.PaginationResult, error) {
	var profiles []model.Profile
	var total int64

	offset := (pagination.Page - 1) * pagination.PageSize

	// Count total records
	if err := h.db.Model(&model.Profile{}).Count(&total).Error; err != nil {
		return nil, err
	}

	// Get paginated results
	if err := h.db.Order("created_at DESC").Offset(int(offset)).Limit(int(pagination.PageSize)).Find(&profiles).Error; err != nil {
		return nil, err
	}

	return &common.PaginationResult{
		Count:   total,
		Results: profiles,
	}, nil
}

func (h *homepageDAO) UpdateProfile(id string, profile *model.Profile) error {
	return h.db.Where("id = ?", id).Updates(profile).Error
}

func (h *homepageDAO) DeleteProfile(id string) error {
	return h.db.Where("id = ?", id).Delete(&model.Profile{}).Error
}

// User operations
func (h *homepageDAO) CreateUser(user *model.User) error {
	return h.db.Create(user).Error
}

func (h *homepageDAO) GetUserByProfileID(profileID string) (*model.User, error) {
	var user model.User
	err := h.db.Where("profile_id = ?", profileID).First(&user).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, nil
	}
	return &user, err
}

func (h *homepageDAO) UpdateUser(profileID string, user *model.User) error {
	return h.db.Where("profile_id = ?", profileID).Updates(user).Error
}

// Video operations
func (h *homepageDAO) CreateVideo(video *model.Video) error {
	return h.db.Create(video).Error
}

func (h *homepageDAO) GetVideosByProfileID(profileID string, pagination *common.Pagination) (*common.PaginationResult, error) {
	var videos []model.Video
	var total int64

	offset := (pagination.Page - 1) * pagination.PageSize

	// Count total records
	if err := h.db.Model(&model.Video{}).Where("profile_id = ?", profileID).Count(&total).Error; err != nil {
		return nil, err
	}

	// Get paginated results
	if err := h.db.Where("profile_id = ?", profileID).Order("publish_time DESC").Offset(int(offset)).Limit(int(pagination.PageSize)).Find(&videos).Error; err != nil {
		return nil, err
	}

	return &common.PaginationResult{
		Count:   total,
		Results: videos,
	}, nil
}

func (h *homepageDAO) GetVideoByID(id string) (*model.Video, error) {
	var video model.Video
	err := h.db.Where("id = ?", id).First(&video).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, nil
	}
	return &video, err
}

func (h *homepageDAO) UpdateVideo(id string, video *model.Video) error {
	return h.db.Where("id = ?", id).Updates(video).Error
}

func (h *homepageDAO) DeleteVideo(id string) error {
	return h.db.Where("id = ?", id).Delete(&model.Video{}).Error
}

func (h *homepageDAO) GetVideos(pagination *common.Pagination) (*common.PaginationResult, error) {
	var videos []model.Video
	var total int64

	offset := (pagination.Page - 1) * pagination.PageSize

	// Count total records
	if err := h.db.Model(&model.Video{}).Count(&total).Error; err != nil {
		return nil, err
	}

	// Get paginated results
	if err := h.db.Order("publish_time DESC").Offset(int(offset)).Limit(int(pagination.PageSize)).Find(&videos).Error; err != nil {
		return nil, err
	}

	return &common.PaginationResult{
		Count:   total,
		Results: videos,
	}, nil
}

// Download operations
func (h *homepageDAO) CreateDownload(download *model.Download) error {
	return h.db.Create(download).Error
}

func (h *homepageDAO) GetDownloadsByVideoID(videoID string) ([]*model.Download, error) {
	var downloads []*model.Download
	err := h.db.Where("video_id = ?", videoID).Find(&downloads).Error
	return downloads, err
}

func (h *homepageDAO) UpdateDownload(id string, download *model.Download) error {
	return h.db.Where("id = ?", id).Updates(download).Error
}

// Stats operations
func (h *homepageDAO) GetStats() (*model.Stats, error) {
	var stats model.Stats

	// Count profiles
	if err := h.db.Model(&model.Profile{}).Count(&stats.ProfileCount).Error; err != nil {
		return nil, err
	}

	// Count videos
	if err := h.db.Model(&model.Video{}).Count(&stats.VideoCount).Error; err != nil {
		return nil, err
	}

	// Count downloaded videos
	if err := h.db.Model(&model.Video{}).Where("download_status = ?", "completed").Count(&stats.DownloadedCount).Error; err != nil {
		return nil, err
	}

	return &stats, nil
}

// Advanced Video operations
func (h *homepageDAO) GetVideosWithFilter(filter map[string]interface{}, pagination *common.Pagination, sortBy, sortOrder string) (*common.PaginationResult, error) {
	var videos []model.Video
	var total int64

	offset := (pagination.Page - 1) * pagination.PageSize

	// Build query with filters
	query := h.db.Model(&model.Video{})

	for key, value := range filter {
		switch key {
		case "profile_id":
			if v, ok := value.(string); ok && v != "" {
				query = query.Where("profile_id = ?", v)
			}
		case "platform":
			if v, ok := value.(string); ok && v != "" {
				query = query.Where("platform = ?", v)
			}
		case "download_status":
			if v, ok := value.(string); ok && v != "" {
				query = query.Where("download_status = ?", v)
			}
		case "author":
			if v, ok := value.(string); ok && v != "" {
				query = query.Where("author LIKE ?", "%"+v+"%")
			}
		case "has_product":
			if v, ok := value.(bool); ok {
				query = query.Where("has_product = ?", v)
			}
		case "start_date":
			if v, ok := value.(string); ok && v != "" {
				query = query.Where("publish_time >= ?", v)
			}
		case "end_date":
			if v, ok := value.(string); ok && v != "" {
				query = query.Where("publish_time <= ?", v)
			}
		case "min_view_count":
			if v, ok := value.(int); ok {
				query = query.Where("view_count >= ?", v)
			}
		case "max_view_count":
			if v, ok := value.(int); ok {
				query = query.Where("view_count <= ?", v)
			}
		case "min_like_count":
			if v, ok := value.(int); ok {
				query = query.Where("like_count >= ?", v)
			}
		case "max_like_count":
			if v, ok := value.(int); ok {
				query = query.Where("like_count <= ?", v)
			}
		case "keywords":
			if v, ok := value.(string); ok && v != "" {
				query = query.Where("title LIKE ? OR description LIKE ? OR keywords LIKE ? OR audio_text LIKE ?",
					"%"+v+"%", "%"+v+"%", "%"+v+"%", "%"+v+"%")
			}
		}
	}

	// Count total records
	if err := query.Count(&total).Error; err != nil {
		return nil, err
	}

	// Apply sorting
	if sortBy == "" {
		sortBy = "publish_time"
	}
	if sortOrder == "" {
		sortOrder = "desc"
	}

	validSortFields := map[string]bool{
		"publish_time": true,
		"view_count":   true,
		"like_count":   true,
		"created_at":   true,
		"title":        true,
	}

	if !validSortFields[sortBy] {
		sortBy = "publish_time"
	}

	if sortOrder != "asc" && sortOrder != "desc" {
		sortOrder = "desc"
	}

	orderClause := sortBy + " " + sortOrder

	// Get paginated results
	if err := query.Order(orderClause).Offset(int(offset)).Limit(int(pagination.PageSize)).Find(&videos).Error; err != nil {
		return nil, err
	}

	return &common.PaginationResult{
		Count:   total,
		Results: videos,
	}, nil
}

func (h *homepageDAO) BatchUpdateVideoStatus(videoIDs []string, status string) error {
	return h.db.Model(&model.Video{}).Where("id IN ?", videoIDs).Update("download_status", status).Error
}

func (h *homepageDAO) BatchDeleteVideos(videoIDs []string) error {
	return h.db.Where("id IN ?", videoIDs).Delete(&model.Video{}).Error
}

func (h *homepageDAO) GetVideoStats(filter map[string]interface{}) (*model.VideoStats, error) {
	var stats model.VideoStats

	// Build query with filters
	query := h.db.Model(&model.Video{})

	for key, value := range filter {
		switch key {
		case "profile_id":
			if v, ok := value.(string); ok && v != "" {
				query = query.Where("profile_id = ?", v)
			}
		case "platform":
			if v, ok := value.(string); ok && v != "" {
				query = query.Where("platform = ?", v)
			}
		case "start_date":
			if v, ok := value.(string); ok && v != "" {
				query = query.Where("publish_time >= ?", v)
			}
		case "end_date":
			if v, ok := value.(string); ok && v != "" {
				query = query.Where("publish_time <= ?", v)
			}
		}
	}

	// Get basic counts
	if err := query.Count(&stats.TotalVideos).Error; err != nil {
		return nil, err
	}

	// Get aggregated statistics
	var result struct {
		TotalViewCount    int64   `json:"total_view_count"`
		TotalLikeCount    int64   `json:"total_like_count"`
		TotalComments     int64   `json:"total_comments"`
		TotalShares       int64   `json:"total_shares"`
		AvgViewCount      float64 `json:"avg_view_count"`
		AvgLikeCount      float64 `json:"avg_like_count"`
		ProductVideoCount int64   `json:"product_video_count"`
	}

	if err := query.Select(`
		COALESCE(SUM(view_count), 0) as total_view_count,
		COALESCE(SUM(like_count), 0) as total_like_count,
		COALESCE(SUM(comment_count), 0) as total_comments,
		COALESCE(SUM(share_count), 0) as total_shares,
		COALESCE(AVG(view_count), 0) as avg_view_count,
		COALESCE(AVG(like_count), 0) as avg_like_count,
		COALESCE(SUM(CASE WHEN has_product = true THEN 1 ELSE 0 END), 0) as product_video_count
	`).Scan(&result).Error; err != nil {
		return nil, err
	}

	stats.TotalViewCount = result.TotalViewCount
	stats.TotalLikeCount = result.TotalLikeCount
	stats.TotalComments = result.TotalComments
	stats.TotalShares = result.TotalShares
	stats.AvgViewCount = result.AvgViewCount
	stats.AvgLikeCount = result.AvgLikeCount
	stats.ProductVideoCount = result.ProductVideoCount

	// Get download status counts
	var downloadedCount, pendingCount, failedCount int64

	query.Where("download_status = ?", "completed").Count(&downloadedCount)
	query.Where("download_status = ?", "pending").Count(&pendingCount)
	query.Where("download_status = ?", "failed").Count(&failedCount)

	stats.DownloadedCount = downloadedCount
	stats.PendingCount = pendingCount
	stats.FailedCount = failedCount

	return &stats, nil
}
